home *** CD-ROM | disk | FTP | other *** search
- /*
- * MULTI-CHANNEL MEMO DISTRIBUTION FACILITY (MMDF)
- *
- *
- * Copyright (C) 1979,1980,1981 University of Delaware
- *
- * Department of Electrical Engineering
- * University of Delaware
- * Newark, Delaware 19711
- *
- * Phone: (302) 738-1163
- *
- *
- * This program module was developed as part of the University
- * of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
- *
- * Acquisition, use, and distribution of this module and its listings
- * are subject restricted to the terms of a license agreement.
- * Documents describing systems using this module must cite its source.
- *
- * The above statements must be retained with all copies of this
- * program and may not be removed without the consent of the
- * University of Delaware.
- *
- *
- * version -1 David H. Crocker March 1979
- * version 0 David H. Crocker April 1980
- * version v7 David H. Crocker May 1981
- * version 1 David H. Crocker October 1981
- *
- */
- /* MAIL-COMMANDS FOR SMTP MAIL */
-
- /* Oct 82 Dave Crocker derived from arpanet ftp/ncp channel
- *
- * -------------------------------------------------
- *
- * Feb 83 Doug Kingston major rewrite, some fragments kept
- */
-
- #include "util.h"
- #include "mmdf.h"
- #include "ch.h"
- #include <signal.h>
- #include "phs.h"
- #include "ap.h"
- #include "dm.h"
- #include "smtp.h"
- #include <netinet/in.h>
-
- extern LLog *logptr;
- extern Chan *chanptr;
- extern char *blt();
- extern char *strdup();
- extern char *strncpy ();
-
- LOCFUN sm_rrec();
-
- char *sm_curname;
-
- struct sm_rstruct sm_rp; /* save last reply obtained */
- LOCVAR Chan *sm_chptr; /* structure for channel that we are */
- FILE *sm_rfp, *sm_wfp;
- LOCVAR char sm_rnotext[] = "No reply text given";
- LOCVAR char netobuf[BUFSIZ];
- LOCVAR char netibuf[BUFSIZ];
-
- /**/
-
- sm_wfrom (sender)
- char *sender;
- {
- char linebuf[LINESIZE];
-
- sprintf (linebuf, "MAIL FROM:<%s>", sender);
- if (rp_isbad (sm_cmd (linebuf, SM_STIME)))
- return (RP_DHST);
-
- switch( sm_rp.sm_rval ) {
- case 250:
- break; /* We're off and running! */
-
- case 500:
- case 501:
- case 552:
- return( sm_rp.sm_rval = RP_PARM );
-
- case 421:
- case 450:
- case 451:
- case 452:
- return( sm_rp.sm_rval = RP_AGN);
-
- default:
- return( sm_rp.sm_rval = RP_BHST);
- }
- return( RP_OK );
- }
-
- sm_wto (host, adr) /* send one address spec to local */
- char host[]; /* "next" location part of address */
- char adr[]; /* rest of address */
- {
- char linebuf[LINESIZE];
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_wto(%s, %s)", host, adr);
- #endif
-
- sprintf (linebuf, "RCPT TO:<%s>", adr);
- if (rp_isbad (sm_cmd (linebuf, SM_TTIME)))
- return (RP_DHST);
-
- switch (sm_rp.sm_rval)
- {
- case 250:
- case 251:
- sm_rp.sm_rval = RP_AOK;
- break;
-
- case 421:
- case 450:
- case 451:
- case 452:
- sm_rp.sm_rval = RP_AGN;
- break;
-
- case 550:
- case 551:
- case 552:
- case 553:
- case 554: /* BOGUS: sendmail is out of spec! */
- sm_rp.sm_rval = RP_USER;
- break;
-
- case 500:
- case 501:
- sm_rp.sm_rval = RP_PARM;
- break;
-
- default:
- sm_rp.sm_rval = RP_RPLY;
- }
- return (sm_rp.sm_rval);
- }
-
- sm_init (curchan) /* session initialization */
- Chan *curchan; /* name of channel */
- {
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_init ()");
- #endif
- sm_chptr = curchan;
- phs_note (sm_chptr, PHS_CNSTRT);
- return (RP_OK); /* generally, a no-op */
- }
-
- /**/
-
- LOCFUN
- sm_irdrply () /* get net reply & stuff into sm_rp */
- {
- static char sep[] = "; "; /* for sticking multi-lines together */
- short len,
- tmpreply,
- retval;
- char linebuf[LINESIZE];
- char tmpmore;
- register char *linestrt; /* to bypass bad initial chars in buf */
- register short i;
- register char more; /* are there continuation lines? */
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_irdrply ()");
- #endif
-
- newrply:
- for (more = FALSE, sm_rp.sm_rgot = FALSE, sm_rp.sm_rlen = 0;
- rp_isgood (retval = sm_rrec (linebuf, &len));)
- { /* 1st col in linebuf gets reply code */
- printx("<-(%s)\r\n", linebuf);
- fflush( stdout );
-
- for (linestrt = linebuf; /* skip leading baddies, probably */
- len > 0 && /* from a lousy Multics */
- (!isascii ((char) *linestrt) ||
- !isdigit ((char) *linestrt));
- linestrt++, len--);
-
- tmpmore = FALSE; /* start fresh */
- tmpreply = atoi (linestrt);
- blt (linestrt, sm_rp.sm_rstr, 3); /* Grab reply code */
- if ((len -= 3) > 0)
- {
- linestrt += 3;
- if (len > 0 && *linestrt == '-')
- {
- tmpmore = TRUE;
- linestrt++;
- if (--len > 0)
- for (; len > 0 && isspace (*linestrt); linestrt++, len--);
- }
- }
-
- if (more) /* save reply value from 1st line */
- { /* we at end of continued reply? */
- if (tmpreply != sm_rp.sm_rval || tmpmore)
- continue;
- more = FALSE; /* end of continuation */
- }
- else /* not in continuation state */
- {
- sm_rp.sm_rval = tmpreply;
- more = tmpmore; /* more lines to follow? */
-
- if (len <= 0)
- { /* fake it, if no text given */
- blt (sm_rnotext, linestrt = linebuf,
- (sizeof sm_rnotext) - 1);
- len = (sizeof sm_rnotext) - 1;
- }
- }
-
- if ((i = min (len, (LINESIZE - 1) - sm_rp.sm_rlen)) > 0)
- { /* if room left, save the human text */
- blt (linestrt, &sm_rp.sm_rstr[sm_rp.sm_rlen], i);
- sm_rp.sm_rlen += i;
- if (more && sm_rp.sm_rlen < (LINESIZE - 4))
- { /* put a separator between lines */
- blt (sep, &(sm_rp.sm_rstr[sm_rp.sm_rlen]), (sizeof sep) - 1);
- sm_rp.sm_rlen += (sizeof sep) - 1;
- }
- }
- #ifdef DEBUG
- else
- ll_log (logptr, LLOGFTR, "skipping");
- #endif
-
- if (!more)
- {
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "(%u)%s", sm_rp.sm_rval, sm_rp.sm_rstr);
- #endif
- if (sm_rp.sm_rval < 100)
- goto newrply; /* skip info messages */
-
- sm_rp.sm_rgot = TRUE;
- return (RP_OK);
- }
- }
- return (retval); /* error return */
- }
-
- sm_rpcpy (rp, len) /* return arpanet command reply */
- RP_Buf *rp; /* where to put it */
- short *len; /* its length */
- {
- if( sm_rp.sm_rgot == FALSE )
- return( RP_RPLY );
-
- rp -> rp_val = sm_rp.sm_rval;
- *len = sm_rp.sm_rlen;
- blt (sm_rp.sm_rstr, rp -> rp_line, sm_rp.sm_rlen + 1);
- sm_rp.sm_rgot = FALSE; /* flag as empty */
-
- return (RP_OK);
- }
- /**/
-
- LOCFUN
- sm_rrec (linebuf, len) /* read a reply record from net */
- char *linebuf; /* where to stuff text */
- short *len; /* where to stuff length */
- {
- extern int errno;
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_rrec ()");
- #endif
-
- *len = 0; /* for clean logging if nothing read */
- linebuf[0] = '\0';
-
- if (fgets (linebuf, LINESIZE, sm_rfp) == NULL) {
- printx("sm_rrec: fgets returns NULL, errno = %d\n", errno);
- }
- *len = strlen (linebuf);
-
- if (ferror (sm_rfp) || feof (sm_rfp))
- { /* error or unexpected eof */
- printx ("sm_rrec: problem reading from net, ");
- printx("netread: ret=%d, fd=%d, ", *len, fileno (sm_rfp));
- fflush (stdout);
- ll_err(logptr, LLOGTMP, "netread: ret=%d, fd=%d",
- *len, fileno (sm_rfp));
- sm_nclose (NOTOK); /* since it won't work anymore */
- return (RP_BHST);
- }
- if (linebuf[*len - 1] != '\n')
- {
- ll_log (logptr, LLOGTMP, "net input overflow");
- while (getc (sm_rfp) != '\n'
- && !ferror (sm_rfp) && !feof (sm_rfp));
- }
- else
- if (linebuf[*len - 2] == '\r')
- *len -= 1; /* get rid of crlf or just lf */
-
- linebuf[*len - 1] = '\0';
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "(%u)'%s'", *len, linebuf);
- #endif
- return (RP_OK);
- }
- /**/
-
- sm_cmd (cmd, time) /* Send a command */
- char *cmd;
- int time; /* Max time for sending and getting reply */
- {
- short retval;
- extern char *sys_errlist[];
- extern int errno;
-
- ll_log (logptr, LLOGPTR, "sm_cmd (%s)", cmd);
-
- printx("->(%s)\r\n", cmd);
- fflush( stdout );
-
- if (setjmp(timerest)) {
- printx("cmd = '%s'; errno = %d\n", cmd, sys_errlist[errno]);
- ll_log (logptr, LLOGGEN,
- "sm_cmd(): timed out after %d sec, cmd %.10s",time,cmd);
- sm_nclose (NOTOK);
- return (sm_rp.sm_rval = RP_DHST);
- }
- s_alarm( (unsigned) time );
- if (fprintf(sm_wfp, "%s\r\n", cmd) == EOF) {
- /* if (fwrite (cmd, sizeof (char), strlen(cmd), sm_wfp) == 0) { */
- printx("fprintf returned EOF, errno=%d\n", errno);
- }
- if (fflush (sm_wfp) == EOF) {
- printx("first fflush returned EOF, errno = %d\n", errno);
- }
- /* fputs ("\r\n", sm_wfp);
- * if (fflush (sm_wfp) == EOF) {
- * printx("second fflush returned EOF, errno = %d\n", errno);
- * }
- */
-
- if (ferror (sm_wfp))
- {
- s_alarm ( 0 );
- ll_log (logptr, LLOGGEN, "sm_cmd(): host died?");
- sm_nclose (NOTOK);
- return (sm_rp.sm_rval = RP_DHST);
- }
-
- if (rp_isbad (retval = sm_irdrply ())) {
- s_alarm( 0 );
- return( sm_rp.sm_rval = retval );
- }
- s_alarm( 0 );
- return (RP_OK);
- }
- /**/
-
- sm_wstm (buf, len) /* write some message text out */
- char *buf; /* what to write */
- register int len; /* how long it is */
- {
- static char lastchar = 0;
- short retval;
- register char *bufptr;
- register char newline;
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_wstm () (%u)'%s'", len, buf ? buf : "");
- #endif
-
- if (buf == 0 && len == 0)
- { /* end of text */
- if (lastchar != '\n') /* make sure it ends cleanly */
- fputs ("\r\n", sm_wfp);
- if (ferror (sm_wfp))
- return (RP_DHST);
- lastchar = 0; /* reset for next message */
- retval = RP_OK;
- }
- else
- {
- newline = (lastchar == '\n') ? TRUE : FALSE;
- for (bufptr = buf; len--; bufptr++)
- {
- switch (*bufptr) /* cycle through the buffer */
- {
- case '\n': /* Telnet requires crlf */
- newline = TRUE;
- putc ('\r', sm_wfp);
- break;
-
- case '.': /* Insert extra period at beginning */
- if (newline)
- putc ('.', sm_wfp);
- /* DROP ON THROUGH */
- default:
- newline = FALSE;
- }
- putc ((lastchar = *bufptr), sm_wfp);
- if (ferror (sm_wfp))
- return (RP_DHST);
- /* finally send the data character */
- }
- retval = ferror(sm_wfp) ? RP_DHST : RP_OK;
- }
-
- return (retval);
- }
-
- /**/
-
- union Haddru {
- long hnum;
- char hbyte[4];
- };
-
- sm_hostid (hostnam, addr, first) /* addresses to try if sending to hostnam */
- char *hostnam; /* name of host */
- union Haddru *addr;
- int first; /* first try on this name ?*/
- {
- int argc;
- register long n;
- char *argv[20];
- char numstr[50];
- int rval;
- int tlookup=1; /* used table lookup? */
-
- #ifdef DEBUG
- ll_log (logptr, LLOGBTR, "sm_gethostid (%s)", hostnam);
- #endif
-
- for (;;)
- {
- /* look for [x.x.x.x] format -- don't need table lookup */
-
- if (hostnam[0] == '[')
- {
- tlookup = 0;
- (void) strncpy(numstr,hostnam,sizeof(numstr)-1);
- }
- else if ((rval=tb_k2val(sm_chptr->ch_table,first,hostnam,numstr))!=OK)
- {
- /* No such host */
- if (first)
- ll_log (logptr, LLOGTMP, "channel '%s' unknown host '%s'",
- sm_chptr -> ch_name, hostnam);
-
- if (rval == MAYBE)
- return(RP_NS);
-
- return(RP_BHST);
- }
-
- ll_log ( logptr, LLOGFTR, "Trying to break down %s", numstr) ;
-
- /* watch out for quoted and bracketed strings */
- argc = cstr2arg ((numstr[0]=='"' || numstr[0]=='[') ? &numstr[1]:numstr,
- 20, argv, '.');
-
- ll_log ( logptr, LLOGFTR, "%d fields, '%s'", argc, argv[0] );
-
-
- switch (argc) /* what form is hostnum in? */
- {
- case 4: /* dot-separated */
- n = atoi (argv[0]);
- n = (n<<8) | atoi (argv[1]);
- n = (n<<8) | atoi (argv[2]);
- addr->hnum = (n<<8) | atoi (argv[3]);
- return(RP_OK);
- break;
-
- default:
- ll_log (logptr, LLOGTMP,
- "channel '%s' host %s' has bad address format",
- sm_chptr -> ch_name, hostnam);
- if (!tlookup)
- {
- /* bad hostname in brackets */
- return(RP_NO);
- }
- break;
- }
- } /* end for */
-
- /* NOTREACHED */
- }
-
- sm_nopen( hostnam )
- char *hostnam;
- {
- Pip fds;
- short retval;
- char linebuf[LINESIZE];
- union Haddru haddr;
- unsigned atime;
- int first;
- int rval;
- extern char *inet_ntoa();
- struct in_addr haddr1;
-
- ll_log (logptr, LLOGPTR, "[ %s ]", hostnam);
-
- printx ("trying...\n");
- fflush (stdout);
- first = 1;
- atime = SM_ATIME;
-
- /* keep coming here until connected or no more addresses */
- retry:
-
- if ((rval = sm_hostid(hostnam, &haddr, first)) != RP_OK)
- {
- switch (rval)
- {
- case RP_NS:
- printx("\tno answer from nameserver\n");
- break;
-
- case RP_NO:
- printx("\tbad hostname format\n");
- break;
-
- default:
- /* some non-fatal error */
- rval = RP_BHST;
- break;
- }
- fflush(stdout);
- return(rval);
- }
-
- if (first)
- first = 0;
-
- haddr1.s_addr = htonl(haddr.hnum);
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR, "trying %s",inet_ntoa(haddr1));
- #endif
-
- /* tell them who we are trying */
- printx("\tconnecting to [%s]...",inet_ntoa(haddr1));
- fflush(stdout);
-
- /* SMTP is on socket 25 */
- retval = tc_uicp (haddr.hnum, 25L, SM_OTIME, &fds);
-
- if (retval != RP_OK)
- {
- /* common event, so LLOGGEN (not TMP) */
- if (retval == RP_TIME) {
- ll_err (logptr, LLOGGEN, "%s (%8lx) open timeout", hostnam, haddr.hnum);
- printx (" timeout...\n");
- } else {
- ll_err (logptr, LLOGGEN, "%s (%8lx) no open", hostnam, haddr.hnum);
- printx (" can't...\n");
- }
- fflush (stdout);
- goto retry; /* can't reach -- try someone else */
- }
- else
- {
- ll_log(logptr, LLOGGEN,"sending to %s via %s",
- hostnam,inet_ntoa(haddr1));
- #ifdef DEBUG
- ll_log (logptr, LLOGFTR,
- "fdr = %d,fdw = %d", fds.pip.prd, fds.pip.pwrt);
- #endif
- }
-
- sm_curname = strdup(hostnam);
- phs_note (sm_chptr, PHS_CNGOT);
- if ((sm_rfp = fdopen (fds.pip.prd, "r")) == NULL ||
- (sm_wfp = fdopen (fds.pip.pwrt, "w")) == NULL) {
- printx (" can't fdopen!\n");
- fflush(stdout);
- return (RP_LIO); /* new address won't fix this problem */
- }
- printx (" open.\n");
- fflush (stdout);
-
- setbuf (sm_wfp, netobuf);
- setbuf (sm_rfp, netibuf);
-
- if (setjmp(timerest)) {
- sm_nclose (NOTOK);
- goto retry; /* too slow, try someone else */
- }
- s_alarm (atime);
-
- atime -= SM_ATINC;
- if (atime < SM_ATMIN)
- atime = SM_ATMIN;
-
- if (rp_isbad (retval = sm_irdrply ())) {
- s_alarm (0);
- sm_nclose (NOTOK);
- goto retry; /* problem reading -- try someone else */
- }
- s_alarm (0);
-
- if( sm_rp.sm_rval != 220 )
- {
- sm_nclose (NOTOK);
- goto retry;
- }
-
- if (sm_chptr -> ch_confstr)
- sprintf (linebuf, "HELO %s", sm_chptr -> ch_confstr);
- else
- sprintf (linebuf, "HELO %s.%s", sm_chptr -> ch_lname,
- sm_chptr -> ch_ldomain);
- if (rp_isbad (sm_cmd( linebuf, SM_HTIME )) || sm_rp.sm_rval != 250 ) {
- sm_nclose (NOTOK);
- goto retry; /* try more intelligent host? */
- }
- return (RP_OK);
- }
- /**/
-
- sm_nclose (type) /* end current connection */
- short type; /* clean or dirty ending */
- {
- if (type == OK) {
- sm_cmd ("QUIT", SM_QTIME);
- } else {
- printx ("\r\nDropping connection\r\n");
- fflush (stdout);
- }
- if (sm_curname)
- free(sm_curname);
- sm_curname = 0;
- if (setjmp(timerest)) {
- return;
- }
- s_alarm (15);
- if (sm_rfp != NULL)
- fclose (sm_rfp);
- if (sm_wfp != NULL)
- fclose (sm_wfp);
- s_alarm (0);
- sm_rfp = sm_wfp = NULL;
- phs_note (sm_chptr, PHS_CNEND);
- }
-